﻿using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace MishraReader.Services
{
    [ContractClass(typeof(IFacebookApiContract))]
    public interface IFacebookApi
    {
        string AppId { get; set; }
        string AppSecret { get; set; }
        bool AdditionalInputRequired(Uri uri);

        Task<string> ExchangeCodeForAccessTokenAsync(string code, CancellationToken cancellationToken = default(CancellationToken));
        Uri GetLoginUrl(IDictionary<string, object> parameters);

        bool TryParseResult(Uri uri, out IFacebookResult result);
    }

    [ContractClassFor(typeof(IFacebookApi))]
    internal abstract class IFacebookApiContract : IFacebookApi
    {
        public abstract string AppId { get; set; }
        public abstract string AppSecret { get; set; }

        public bool AdditionalInputRequired(Uri uri)
        {
            Contract.Requires<ArgumentNullException>(uri != null, "uri");
            return false;
        }

        public Task<string> ExchangeCodeForAccessTokenAsync(string code, CancellationToken cancellationToken = new CancellationToken())
        {
            Contract.Requires<InvalidOperationException>(!string.IsNullOrEmpty(AppId));
            Contract.Requires<InvalidOperationException>(!string.IsNullOrEmpty(AppSecret));
            Contract.Requires<ArgumentException>(!string.IsNullOrEmpty(code));
            Contract.Ensures(Contract.Result<Task<string>>() != null);

            return null;
        }

        public Uri GetLoginUrl(IDictionary<string, object> parameters)
        {
            Contract.Requires<InvalidOperationException>(!string.IsNullOrEmpty(AppId));
            Contract.Requires<InvalidOperationException>(!string.IsNullOrEmpty(AppSecret));
            Contract.Requires<ArgumentNullException>(parameters != null, "parameters");
            Contract.Ensures(Contract.Result<Uri>() != null);

            return null;
        }

        public bool TryParseResult(Uri uri, out IFacebookResult result)
        {
            Contract.Ensures((Contract.Result<bool>() && Contract.ValueAtReturn(out result) != null) ||
                            (!Contract.Result<bool>() && Contract.ValueAtReturn(out result) == null));

            result = null;
            return false;
        }
    }


    [ContractClass(typeof(IFacebookResultContract))]
    public interface IFacebookResult
    {
        string Code { get; }
        bool IsSuccess { get; }
    }

    [ContractClassFor(typeof(IFacebookResult))]
    internal abstract class IFacebookResultContract : IFacebookResult
    {
        public string Code
        {
            get
            {
                Contract.Ensures((IsSuccess && !String.IsNullOrEmpty(Contract.Result<string>()))
                                 || (!IsSuccess));
                return null;
            }
        }
        public abstract bool IsSuccess { get; }
    }

}